package org.noote.spidy.monitor;


import java.text.DecimalFormat;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;

import org.noote.libs.camera.broadcast.CameraClient;
import org.noote.libs.graphicbuffer.FPSCounter;
import org.noote.libs.graphicbuffer.GraphicBuffer;
import org.noote.libs.robot.Robot_ServoMotor;
import org.noote.libs.spidy.anim.Spidy_WildRobot;
import org.noote.libs.spidy.comm.IPCommandEvents;
import org.noote.libs.spidy.comm.IPCommandProtocol;
import org.noote.libs.spidy.configuration.RobotSettings;
import org.noote.libs.spidy.configuration.RobotStates;
import org.noote.libs.tcpip.IPClient;
import org.noote.libs.tcpip.helper.Helper_WiFi;

import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

@SuppressLint("HandlerLeak")
public class Spidy_Activity extends Activity {

	static final String TAG = "Spidy_Activity";
	
	static DecimalFormat m_dfFPS = new DecimalFormat("#,##0.00");
	
	//
	public static final String PREFS_NAME = "Robot_Monitor";
	public static final String PREFS_NAME_IPADDRESS = "IP Address";
	
	protected static final int MESSAGE_UI_SHOWTOAST = 0;
	protected static final int MESSAGE_UI_ADDLOG = 1;
	protected static final int MESSAGE_UI_UPDATE_FPSCOUNTER = 2;

	private String _sAddressDevice = "";

	protected int _iReadyStep = 0;
	protected boolean _bTransmitData = false;

	protected boolean _bCameraPreview = false;
	protected String _sCameraHostname = "";
	protected int _iCameraPort = 0;
	
	private RobotSettings _settings = new RobotSettings();
	RobotStates _states = new RobotStates();

	Spidy_WildRobot _bot;
	Spidy_Skeleton3D _bot3d;
	
	FPSCounter _botFrameCounter = new FPSCounter();
	
	PowerManager.WakeLock wl = null;

	private IPClient _IPClient = null;
	
	private Spidy_GLView _glView = null;
	private Spidy_CameraClient _cameraView = null;
	
	private TextView _textLog = null;
	private ToggleButton _toggleButtonConnection = null, _toggleButtonTransmission = null, _toggleButtonCamera = null;
       
    boolean _move_front = false, _move_back = false;
    boolean _move_up = false, _move_down = false;
    boolean _rotate_left = false, _rotate_right = false;
    
    int _iAnimationChoosen=0;
		
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
		setContentView(R.layout.monitor);

        _IPClient = new IPClient(mIPEvents);
        
        _textLog = (TextView)findViewById(R.id.textLog);
        _textLog.setMovementMethod(new ScrollingMovementMethod());
        
        _glView = new Spidy_GLView(this, getApplicationContext());
        ((FrameLayout) findViewById(R.id.layoutGL)).addView(_glView);
        
        _cameraView = new Spidy_CameraClient(this);
		((FrameLayout) findViewById(R.id.layoutCamera)).addView(_cameraView);
		
		_cameraView.setOnEventListener(new CameraClient.onEventListener()
		{
			@Override
			public void onConnected()
			{
				addLog("ipCamera connected");
				if(_bCameraPreview)
					_cameraView.askImage();
			}
			@Override
			public void onDisconnected()
			{
				addLog("ipCamera disconnected");
			}
			@Override
			public void onError(String sMessage)
			{
				addLog("ipCamera error : " + sMessage);				
			}
			
			@Override
			public void onGrabbedFrame(GraphicBuffer frame)
			{
				// ok get a frame and ask for a new one !
				if(_bCameraPreview)
					_cameraView.askImage();
			}
		});
		
		Button buttonSettings = (Button)findViewById(R.id.buttonSettings);
		buttonSettings.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View v) {
				showSettings();
			}
		});

		_toggleButtonConnection = (ToggleButton)findViewById(R.id.toggleButtonConnection);
		_toggleButtonConnection.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View v) {
				if(_toggleButtonConnection.isChecked())
				{
					ipConnect();
				}
				else
				{
					ipDisconnect();					
				}
			}
		});
		
		_toggleButtonTransmission = (ToggleButton)findViewById(R.id.toggleButtonTransmission);
		_toggleButtonTransmission.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View v) {
				if(_toggleButtonTransmission.isChecked())
				{
					_bTransmitData = false;
				}
				else
				{
					_bTransmitData = true;
				}
			}
		});
		
		_toggleButtonCamera = (ToggleButton)findViewById(R.id.toggleButtonCamera);
		_toggleButtonCamera.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View v) {
				if(_toggleButtonCamera.isChecked())
				{
					_bCameraPreview = false;
				}
				else
				{
					if(!_cameraView.isConnected())
					{
						if(_cameraView.connect(_sCameraHostname, _iCameraPort))
						{
							_bCameraPreview = true;
							_cameraView.askImage();
						}
					}
				}
			}
		});
   	}

	@Override
    public void onStart() {
        super.onStart();
	}
	
	@Override
	public void onStop()
	{
		super.onStop();
	}

    @Override
    protected void onPause() {
        super.onPause();
        
        addLog("Go sleeping...");
        
        if(_glView != null)	_glView.onPause();
        
		if(wl != null ) wl.release();        
    }

    @Override
    protected void onResume() {
        super.onResume();
        
        if(_glView != null)	_glView.onResume();
        
		if(wl == null)
		{
			PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
		    wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "Remote Robot");
		}
		if(wl != null ) wl.acquire();
		
        addLog("Back on business !");
    }
    
    protected void showSettings() {
		Intent intent = new Intent(this, Settings_Activity.class);
		startActivity(intent);
	}

	@Override
	public void onBackPressed()
    {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(getString(R.string.dlg_exit_title));
		builder.setMessage(getString(R.string.dlg_exit_text));
		builder.setPositiveButton(getString(R.string.dlg_button_exit),
				new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int id) {
						ipDisconnect();
						finish();
					}
				});
		builder.setNegativeButton(getString(R.string.dlg_button_cancel),
				new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int id) {
						dialog.cancel();
					}
				});
		AlertDialog alert = builder.create();
		alert.show();
    }

    
	private boolean  getCurrentIPAddress() {
		String sCurrentIPAddress = Helper_WiFi.getCurrentIPAddress_WiFi_Only(this,
				true);
		if (sCurrentIPAddress == "") {
			new AlertDialog.Builder(this)
					.setTitle("Not WiFi active connexion detected...")
					.setPositiveButton("Ok",
							new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int whichButton) {
									finish();
								}
							}).show();
			return false;
		}
		return true;		
	}
    
    void ipConnect()
    {
    	_toggleButtonConnection.setEnabled(false);
    	_toggleButtonTransmission.setEnabled(false);
		addLog("Try WiFi connection...");
		if(getCurrentIPAddress())
		{
			if(!_IPClient.isConnected())
			{
				String ip[] = _sAddressDevice.split("\\:");
				if(ip.length == 2)
				{
					if(!_IPClient.connect(ip[0], Integer.parseInt(ip[1])))
					{	
						addLog("Connection to WiFi: '"+_sAddressDevice+"' impossible !!!");
						_toggleButtonConnection.setEnabled(true);
						_toggleButtonConnection.setChecked(false);
					}
				}
				else
				{
					addLog("Connection to WiFi: '"+_sAddressDevice+"' is invalid !!!");
					_toggleButtonConnection.setEnabled(true);
					_toggleButtonConnection.setChecked(false);
				}
			}
		}
		else
		{			
			_toggleButtonConnection.setEnabled(true);
			_toggleButtonConnection.setChecked(false);
		}
    }
    void ipDisconnect()
    {
		_states._bReady = false;
		_bTransmitData = false;

    	addLog("Try WiFi disconnection...");
		_IPClient.sendMessage(IPCommandProtocol.sendQuit()); // quit	
		if(_IPClient.isConnected())
		{
			if(!_IPClient.close())
			{
				addLog("Disconnection from WiFi:"+_sAddressDevice+" impossible !!!");
			}
		}
		_toggleButtonConnection.setEnabled(false);
    	_toggleButtonTransmission.setEnabled(false);		
    }

    final IPCommandEvents mIPEvents = new IPCommandEvents()
	{
		@Override
		public void onConnected()
		{
			showToast("Connected");
			
			_toggleButtonConnection.setEnabled(true);
			_toggleButtonTransmission.setEnabled(false);
			_toggleButtonTransmission.setEnabled(false);
			
			_states._bNetworkOnline = true;
			
			addLog("Online...");
			//_IPClient.sendMessage(IPCommandProtocol.sendAskConnection()); // ask connect
		}
		@Override
		public void onDisconnected()
		{
			showToast("Disconnected");
			
        	_states._bNetworkOnline = false;
        	_states._bReady = false;
        	
        	_toggleButtonConnection.setEnabled(true);
        	_toggleButtonConnection.setChecked(false);
	    	_toggleButtonTransmission.setEnabled(false);
	    	_toggleButtonTransmission.setChecked(false);
	    	
			_glView._animation_carousel.enableWindow(false);
		}
		@Override
		public void onError(String sError)
		{
			Log.e(TAG, "Get WiFi error : "+sError);
			showToast("Get Error : " + sError);
       	}
		@Override
		public void onText(String sText)
		{
			Log.i(TAG, "Get WiFi text : "+sText);
			showToast("Get text : " + sText);
		}
		@Override
		public void onReady(String sStatus) {
			Log.i(TAG, "Get WiFi ready : "+sStatus);
			if(sStatus.equalsIgnoreCase("ok") || (sStatus.equalsIgnoreCase("ping") && (_iReadyStep&0x01)!=0x01))
			{
				_iReadyStep |= 0x01;
				
				_IPClient.sendMessage(IPCommandProtocol.sendAskVersion());
				_IPClient.sendMessage(IPCommandProtocol.sendAskSettingCameraBroadcast());
				
				isReady();
			}
			else if(sStatus.equalsIgnoreCase("ping"))
			{
				Log.i(TAG, "Send WiFi alive");
				_IPClient.sendMessage(IPCommandProtocol.sendAlive()); // Yes, i'm alive :
			}
		}
		@Override
		public void onVersion(String robotname, String robotversion)
		{
			_iReadyStep |= 0x2;
			
			_settings._sRobot_Name = robotname;
			_settings._sRobot_Version = robotversion;
			
			_IPClient.sendMessage(IPCommandProtocol.sendAskAllServoPositions()); // ask version
			
			isReady();
		}
		@Override
		public void onTick(final float fTimeSlice) {
			if(_states._bReady && _bTransmitData)
			{
				_botFrameCounter.tick();
				
				_IPClient.sendMessage(_bot.buildTransmitMessage());
				
				updateFPS();
			}
		}
		@Override
		public void onRange(final int iFrontRange) {
			if(_states._bReady && _bTransmitData)
			{
				_states._iFrontRange = iFrontRange;
			}
		}
		@Override
		public void onServoPositions(SparseArray<Float> positions)
		{
			for(Robot_ServoMotor servo : _bot.getServoList())
			{
				Float fPos = positions.get(servo.getID());
				if(fPos != null)
				{
					servo.setRealPosition(fPos.floatValue());
				}
			}
			
			if(_states._bReady == false && (_iReadyStep&0x04)!=0x04)
			{
				_iReadyStep |= 0x04;
				
				isReady();
			}
		}
		
		@Override
		public void onSettingCameraBroadcast(String sHostname, int iPort)
		{
        	_toggleButtonCamera.setEnabled(true);
        	_toggleButtonCamera.setChecked(false);
        	_sCameraHostname = sHostname;
        	_iCameraPort = iPort;
		}

		private void isReady()
		{
    		if(_states._bReady == false && _iReadyStep == (0x01|0x02|0x04))
    		{
    			if(IPCommandProtocol.getProtocolVersion().equalsIgnoreCase(_settings._sRobot_Version))
    			{
	    			_states._bReady = true;
	    			_bTransmitData = true;    			
	    			
	    			addLog("Ready to rule !");
	    			
	    			_glView._animation_carousel.selectItem(0);
	    			_glView._animation_carousel.enableWindow(true);
    			
	    			_toggleButtonConnection.setEnabled(true);
	    			_toggleButtonTransmission.setEnabled(true);
	    			_toggleButtonTransmission.setChecked(true);
    			}
    			else
    			{
    				// Bad protocol version !
    				addLog("Bad protocol version :(");
    				addLog("Requiered version "+IPCommandProtocol.getProtocolVersion()+", robot version is "+_settings._sRobot_Version);
    				
    				ipDisconnect();
    			}
   			}
    		else if(_states._bReady == false)
    		{
    			String sWait = "Wait ";
    			sWait += ((_iReadyStep & 0x01) == 0x01)?"*":".";
    			sWait += ((_iReadyStep & 0x02) == 0x02)?"*":".";
    			sWait += ((_iReadyStep & 0x04) == 0x04)?"*":".";
    			addLog(sWait);

    			_glView._animation_carousel.selectItem(0);
    			_glView._animation_carousel.enableWindow(false);
    		}
		}
	};
	
	public void showToast(String sMsg)
	{
		_UI_Handler.sendMessage(_UI_Handler.obtainMessage(MESSAGE_UI_SHOWTOAST, sMsg));
	}
	
	public void addLog(String sMsg)
	{
		_UI_Handler.sendMessage(_UI_Handler.obtainMessage(MESSAGE_UI_ADDLOG, sMsg));
	}
	public void updateFPS()
	{
		_UI_Handler.sendMessage(_UI_Handler.obtainMessage(MESSAGE_UI_UPDATE_FPSCOUNTER, null));
	}

	final Handler _UI_Handler = new Handler() {
	    @Override
		public void handleMessage(Message msg) {
	        switch (msg.what) {
	        case MESSAGE_UI_SHOWTOAST:
	        {
	        	Toast.makeText(getApplicationContext(), (String)msg.obj, Toast.LENGTH_LONG).show();
	        }
	            break;
	        case MESSAGE_UI_ADDLOG:
	        {
	        	String sLog = _textLog.getText().toString();
	        	sLog+=(String)msg.obj;
	        	_textLog.setText(sLog);
	        }
	            break;
	        case MESSAGE_UI_UPDATE_FPSCOUNTER:
	        {
	        	TextView fps = (TextView) findViewById(R.id.textBotFPS);
	        	fps.setText(m_dfFPS.format(_botFrameCounter.getFPS()));
	        }
	            break;
	        }
	    }
	};
}